// 源自Inferno utils/6l/l.h和相关文件。
// https:
// None
// None
// None
// None
// None
// None
// None
// None
// None
// None
// 特此向任何获得副本的人免费授予许可
// 本软件和相关文档文件（“软件”）的
// 在软件中不受限制，包括但不限于权利
// 使用、复制、修改、合并、发布、分发、再许可和/或销售
// 软件的副本，并允许向其提供软件的人员
// 按照以下条件提供：
// None
// 上述版权声明和本许可声明应包含在
// 软件的所有副本或主要部分。
// None
// 本软件按“原样”提供，无任何形式的明示或明示担保
// 默示，包括但不限于适销性保证，
// 适用于特定目的和非侵权。在任何情况下
// 作者或版权持有人应承担任何索赔、损害或其他责任
// 无论是在合同诉讼、侵权诉讼或其他诉讼中，由以下原因引起的责任：，
// 与本软件有关或与本软件的使用或其他交易有关
// 软件。

package ld

import (
	"bufio"
	"cmd/internal/objabi"
	"cmd/internal/sys"
	"cmd/link/internal/loader"
	"cmd/link/internal/sym"
	"debug/elf"
	"fmt"
)

type Shlib struct {
	Path string
	Hash []byte
	Deps []string
	File *elf.File
}

// Link保存从编译器编写目标代码的上下文
// 或用于将该输入读入链接器。
type Link struct {
	Target
	ErrorReporter
	ArchSyms

	outSem chan int // 限制输出写入程序的数量
	Out    *OutBuf

	version int // 静态/文件本地符号的当前版本号

	Debugvlog int
	Bso       *bufio.Writer

	Loaded bool // 将所有输入作为符号加载后设置

	compressDWARF bool

	Libdir       []string
	Library      []*sym.Library
	LibraryByPkg map[string]*sym.Library
	Shlibs       []Shlib
	Textp        []loader.Sym
	Moduledata   loader.Sym

	PackageFile  map[string]string
	PackageShlib map[string]string

	tramps []loader.Sym // 蹦床

	compUnits []*sym.CompilationUnit // 矮化编译单元
	runtimeCU *sym.CompilationUnit   // 一个运行时CU，最后一个看到的。

	loader  *loader.Loader
	cgodata []cgodata // 要加载的cgo指令，三个字符串是loadcgo的参数

	datap  []loader.Sym
	dynexp []loader.Sym

	// Elf symtab变量。
	numelfsym int // 从0开始，保留1

	// 这些是由链接器创建和编写的符号。
	// 而不是创建符号并将其所有数据写入堆，
	// 您可以创建一个符号，只调用一个生成函数
	// 在输出mmap中创建符号后。
	generatorSyms map[loader.Sym]generatorFunc
}

type cgodata struct {
	file       string
	pkg        string
	directives [][]string
}

// 从硬件堆栈指针到本地
// 堆栈上的变量。使用链接寄存器的体系结构可以保存其值
// 在函数序言中的堆栈上，因此始终在
// 硬件堆栈指针和局部变量区域。
func (ctxt *Link) FixedFrameSize() int64 {
	switch ctxt.Arch.Family {
	case sys.AMD64, sys.I386:
		return 0
	case sys.PPC64:
		// ppc64le上的PIC代码需要32字节的堆栈，并且更容易实现
		// 只要在ppc64x上始终使用那么多堆栈即可。
		return int64(4 * ctxt.Arch.PtrSize)
	default:
		return int64(ctxt.Arch.PtrSize)
	}
}

func (ctxt *Link) Logf(format string, args ...interface{}) {
	fmt.Fprintf(ctxt.Bso, format, args...)
	ctxt.Bso.Flush()
}

func addImports(ctxt *Link, l *sym.Library, pn string) {
	pkg := objabi.PathToPrefix(l.Pkg)
	for _, imp := range l.Autolib {
		lib := addlib(ctxt, pkg, pn, imp.Pkg, imp.Fingerprint)
		if lib != nil {
			l.Imports = append(l.Imports, lib)
		}
	}
	l.Autolib = nil
}

// 分配新版本（即符号命名空间）。
func (ctxt *Link) IncVersion() int {
	ctxt.version++
	return ctxt.version - 1
}

// 返回最大版本号
func (ctxt *Link) MaxVersion() int {
	return ctxt.version
}

// generatorFunc是一种方便的类型。
// 链接器创建的符号很大，不应该真正存在于
// 堆可以定义一个生成器函数，并且可以生成它们的字节
// 直接在输出mmap中。
// None
// 生成器符号不应增大符号大小，可能会被调用
// 未来的平行线。
// None
// 当
// 发电机被称为。
type generatorFunc func(*Link, loader.Sym)

// createGeneratorSymbol是创建生成器的一种方便方法
// 象征
func (ctxt *Link) createGeneratorSymbol(name string, version int, t sym.SymKind, size int64, gen generatorFunc) loader.Sym {
	ldr := ctxt.loader
	s := ldr.LookupOrCreateSym(name, version)
	ldr.SetIsGeneratedSym(s, true)
	sb := ldr.MakeSymbolUpdater(s)
	sb.SetType(t)
	sb.SetSize(size)
	ctxt.generatorSyms[s] = gen
	return s
}
